package com.gitee.qdbp.general.common.biz.files.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import com.gitee.qdbp.general.common.api.files.model.IPathParams;
import com.gitee.qdbp.general.common.api.files.model.PathParams;
import com.gitee.qdbp.tools.files.PathTools;
import com.gitee.qdbp.tools.utils.ConvertTools;
import com.gitee.qdbp.tools.utils.StringTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

public class FileHandleTools {

    /** URI路径分隔符正则表达式 **/
    private static final Pattern URI_SEPARATOR = Pattern.compile("/");

    /**
     * 根据源路径和带占位符的路径配置生成移动后的目标路径<br>
     * <br>
     * 例1: /{tenant-code}/{user-id}/{category}/{year}/{month}/{day}/{random-6}.{ext}<br>
     * 原路径: temps/xx/0/portrait/2018/06/04/123456.png, 注册前上传的路径, 此时没有user-id<br>
     * PathParams.getExtra() = { 'user-id':'100088' }<br>
     * 新路径: files/xx/100088/portrait/2018/06/04/123456.png<br>
     * <br>
     * 例2: /{tenant-code}/U{user-id}-{category}/{year}/{month}/{day}/{random-6}.{ext}<br>
     * 原路径: temps/xx/U0-portrait/2018/06/04/123456.png, 注册前上传的路径, 此时没有user-id<br>
     * PathParams.getExtra() = { 'user-id':'100088' }<br>
     * 新路径: files/xx/U100088-portrait/2018/06/04/123456.png<br>
     * <br>
     * 例3: /{tenant-code}/{user-id}{category}/{year}/{month}/{day}/{random-6}.{ext}<br>
     * 原路径: temps/xx/0portrait/2018/06/04/123456.png, 注册前上传的路径, 此时没有user-id<br>
     * PathParams.getExtra() = { 'tenant-code':'yy', 'user-id':'100088' }<br>
     * 新路径: files/yy/0portrait/2018/06/04/123456.png, <br>
     * <b>{user-id}{category}两个变量之间没有分隔符, 无法处理, 这部分返回原路径</b><br>
     * 
     * @param srcPath 源路径, 带顶级文件夹
     * @param placeholderPath 带占位符的路径配置, 不带顶级文件夹
     * @param params 替换占位符的参数
     * @return 目标路径, 带顶级文件夹
     */
    public static String generateMoveTargetPath(String srcPath, String placeholderPath, IPathParams params) {
        if (srcPath.startsWith("/")) {
            srcPath = srcPath.substring(1);
        }
        if (placeholderPath.startsWith("/")) {
            placeholderPath = placeholderPath.substring(1);
        }

        String srcTopFolder;
        String srcTirmPath;
        { // 拆解为顶级文件夹和路径
            int index = srcPath.indexOf('/');
            if (index < 0) {
                srcTopFolder = null;
                srcTirmPath = srcPath;
            } else {
                srcTopFolder = srcPath.substring(0, index);
                srcTirmPath = srcPath.substring(index + 1);
            }
        }

        // 拆解原路径
        String[] paths = URI_SEPARATOR.split(srcTirmPath);
        String[] vars = URI_SEPARATOR.split(placeholderPath);
        if (vars.length != paths.length) { // 路径不匹配, 无法拆解, 只将第一级非数字的路径去掉
            if (StringTools.isDigit(srcTopFolder)) {
                return PathTools.concat(params.name(), srcTopFolder, srcTirmPath);
            } else {
                return PathTools.concat(params.name(), srcTirmPath);
            }
        } else { // 路径匹配, 从PathParams.getExtra()中取参数替换对应路径
            // 例如: /{tenant-code}/{user-id}/{category}/
            // 原路径: /xx/0/portrait/, 注册前上传的路径, 此时没有user-id
            // PathParams.getExtra() = { 'user-id':'100088' }
            // 新路径: /xx/100088/portrait/
            String[] temp = replacePlaceholder(paths, vars, params);
            return PathTools.concat(params.name(), temp);
        }
    }

    /**
     * 路径替换, 从PathParams.getExtra()中取参数替换对应路径<br>
     * <br>
     * 例1: /{tenant-code}/{user-id}/{category}/<br>
     * 原路径: /xx/0/portrait/, 注册前上传的路径, 此时没有user-id<br>
     * PathParams.getExtra() = { 'user-id':'100088' }<br>
     * 新路径: /xx/100088/portrait/<br>
     * <br>
     * 例2: /{tenant-code}/U{user-id}-{category}/<br>
     * 原路径: /xx/U0-portrait/, 注册前上传的路径, 此时没有user-id<br>
     * PathParams.getExtra() = { 'user-id':'100088' }<br>
     * 新路径: /xx/U100088-portrait/<br>
     * <br>
     * 例3: /{tenant-code}/{user-id}{category}/<br>
     * 原路径: /xx/0portrait/, 注册前上传的路径, 此时没有user-id<br>
     * PathParams.getExtra() = { 'tenant-code':'yy', 'user-id':'100088' }<br>
     * 新路径: /yy/0portrait/, <b>{user-id}{category}两个变量之间没有分隔符, 无法处理, 这部分返回原路径</b><br>
     * 
     * @instance paths 原路径, 如 [xx, u_0-portrait]
     * @param placeholders 带占位符的变量, 如 [{tenant-code}, u_{user-id}-{category}]
     * @param params 替换占位符的参数, 如 { 'user-id':'100088' }
     * @return 替换后的字符串, 如 u_100088-portrait
     */
    private static String[] replacePlaceholder(String[] paths, String[] placeholders, IPathParams params) {

        Map<String, String> map = null;
        if (params instanceof PathParams) {
            PathParams options = (PathParams) params;
            Map<String, Object> temp = options.getExtra();
            if (VerifyTools.isNotBlank(temp)) {
                map = new HashMap<>();
                for (Map.Entry<String, Object> entry : temp.entrySet()) {
                    Object value = entry.getValue();
                    if (value == null) continue;
                    String key;
                    if (entry.getKey().startsWith("{") && entry.getKey().endsWith("}")) {
                        key = entry.getKey();
                    } else {
                        key = "{" + entry.getKey() + "}";
                    }
                    map.put(key, value.toString());
                }
            }
        }
        String[] result = new String[paths.length];
        if (VerifyTools.isBlank(map)) { // 返回源路径
            System.arraycopy(paths, 0, result, 0, result.length);
        } else {
            for (int i = 0; i < placeholders.length; i++) {
                String placeholder = placeholders[i];
                if (map.get(placeholder) != null) { // 如: {tenant-code}
                    result[i] = map.get(placeholder).toString();
                } else { // 如: {user-id}-{category}, 占位符都能替换掉才采用
                    result[i] = replacePlaceholder(placeholder, paths[i], map);
                }
            }
        }
        return result;
    }

    /**
     * 替换占位符
     * 
     * @param placeholder 带占位符的变量, 如 u_{user-id}-{category}
     * @instance bak 找不到占位符时的备用字符串, 如 u_0-portrait
     * @param params 替换占位符的参数, 如 { 'user-id':'100088' }
     * @return 替换后的字符串, 如 u_100088-portrait
     */
    private static String replacePlaceholder(String placeholder, String bak, Map<String, String> params) {
        String[] strings = splitByPlaceholder(placeholder);
        StringBuilder buffer = new StringBuilder();
        String constants = bak;
        for (int i = 0; i < strings.length; i++) {
            String s = strings[i];
            if (s.startsWith("{") && s.endsWith("}")) { // 变量
                // 向后移动常量
                String currConstant = constants;
                String nextConstant = i < strings.length - 1 ? strings[i + 1] : null;
                if (nextConstant != null) {
                    if (nextConstant.startsWith("{") && nextConstant.endsWith("}")) {
                        return bak; // 两个变量之间没有分隔符, 无法处理
                    }
                    int index = constants.indexOf(nextConstant);
                    if (index > 0) {
                        currConstant = constants.substring(0, index);
                        constants = constants.substring(index); // 跟着向后移动
                    } else if (index < 0) {
                        return bak; // bak不符合vars规则
                    }
                }
                if (params.containsKey(s)) {
                    buffer.append(params.get(s));
                } else {
                    buffer.append(currConstant);
                }
            } else { // 常量
                buffer.append(s);
                if (constants.startsWith(s)) {
                    constants = constants.substring(s.length()); // 跟着向后移动
                } else {
                    return bak; // bak不符合vars规则
                }
            }
        }
        return buffer.toString();
    }

    /**
     * 按占位符拆分字符串
     * 
     * @param string 带占位符的字符串, 如 u_{user-id}-{category}
     * @return 拆分后的数组, 如 [u_, {user-id}, -, {category}]
     */
    public static String[] splitByPlaceholder(String string) {
        char[] chars = string.toCharArray();
        StringBuilder buffer = new StringBuilder();
        List<String> list = new ArrayList<>();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == '{') {
                if (buffer.length() > 0) {
                    list.add(buffer.toString());
                    buffer.setLength(0);
                }
                buffer.append(chars[i]);
            } else if (chars[i] == '}') {
                buffer.append(chars[i]);
                list.add(buffer.toString());
                buffer.setLength(0);
            } else {
                buffer.append(chars[i]);
            }
        }
        if (buffer.length() > 0) {
            list.add(buffer.toString());
        }
        return ConvertTools.toArray(list, String.class);
    }

}
